function gewPhongMaterial(effect,name)
{ 
  // general properties
  gewMaterial.call(this,effect,name);
  this.texture = null;
  this.ambient = new gewVec3(1.,1.,1.);
  this.diffuse = new gewVec3(1.,1.,1.);
  this.specular = new gewVec3(1.,1.,1.);
  this.shininess = 10;
  this.faceCulling = true;
  this.alphaRef = 0.0;
  //Private:
  this.batchType = GEW_NO_BATCH;  
  this.modeMatBuf = new WebGLFloatArray(16* GEW_MAX_OBJ_VCB);
}
//gewPhongMaterial.prototype = new gewMaterial();
extend2(gewPhongMaterial,gewMaterial);
gewPhongMaterial.prototype.render = function()
{
  this.isRendering = true;
  // Render node list
  var tex = this.texture;
  var effect = this.effect;
  var shader = effect.shader;
  var scene3d = effect.scene3d;
  var gl = this.gl;
  var ambient = this.ambient;
  var diffuse = this.diffuse;
  var specular = this.specular;
  if(tex&&tex.isReady)
  {   
    if(!this.faceCulling)
      gl.disable(gl.CULL_FACE);
            
    gl.uniform1i(shader.texture0, 0);
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, tex.glName);
    if(shader.shadowMap)
    {
      gl.uniform1i(shader.shadowMap, 1);
      gl.activeTexture(gl.TEXTURE1);
      gl.bindTexture(gl.TEXTURE_2D, scene3d.shadowMap);
    }
    var light_data = scene3d.mainLight.lightData;
    gl.uniform4f(shader.ambient, ambient.x*light_data[3], ambient.y*light_data[4], ambient.z*light_data[5],this.alphaRef);
    gl.uniform4f(shader.diffuse, diffuse.x*light_data[6], diffuse.y*light_data[7], diffuse.z*light_data[8], light_data[9]);
    gl.uniform4f(shader.specular,specular.x*light_data[6],specular.y*light_data[7],specular.z*light_data[8], this.shininess);
    var list  = this.nodeList;
    var listLen = list.length;  
    var previousMesh = null;  
    if (this.batchType == GEW_NO_BATCH) 
    {
      // Bind default obj idx buffer
      var game = effect.game;
      gl.bindBuffer(gl.ARRAY_BUFFER, game.defaultObjIdxGLBuffer);
      gl.vertexAttribPointer(shader.inObjIdx, 1, gl.FLOAT, false, 0, 0);
      for (var i = 0; i < listLen; i++) 
      {
        var node = list[i];
        if(!node.getFlag(NODE_FRUSTUM_IN)||!node.isVisible)
          continue;
        var modelMat = node.modelMat; 
        gl.uniformMatrix4fv(shader.modelMat, false, modelMat.data);
        if( previousMesh!= node.mesh)
        {
          node.setAttributePointers(this);
          previousMesh = node.mesh;
        }
        node.render(this);
      }
    } 
    else if(this.batchType == GEW_VERTEX_CONSTANTS_BATCH)
    {
      var batchs = {};
      // Find the batchs
      for (var i = 0; i < listLen; i++) 
      {
        var node = list[i];
        if(!node.getFlag(NODE_FRUSTUM_IN)||!node.isVisible)
          continue;
        var mesh_name = node.mesh.name;
        if(!batchs[mesh_name])
        {
          var batch = batchs[mesh_name] = {};
          batch.mesh = node.mesh;
          batch.nodeList = [];          
        }
        else
          var batch = batchs[mesh_name];
        batch.nodeList.push(node);
      }
      // Draw all batchs
      for(var i in batchs)
      {
        var batch = batchs[i];
        var m = batch.mesh;
        
        if(!m.isReadyForBatch)
          m.makeVBOForBatch(gl);
                
        // Set atrribute poitters
        gl.bindBuffer(gl.ARRAY_BUFFER, m.batchGLBuffers.positions);
        gl.vertexAttribPointer(shader.inPosition, 3, gl.FLOAT, false, 0, 0);
        gl.bindBuffer(gl.ARRAY_BUFFER, m.batchGLBuffers.objIdx);
        gl.vertexAttribPointer(shader.inObjIdx, 1, gl.FLOAT, false, 0, 0);
        gl.bindBuffer(gl.ARRAY_BUFFER, m.batchGLBuffers.texcoords);
        gl.vertexAttribPointer(shader.inTexCoord0, 2, gl.FLOAT, false, 0, 0);
        gl.bindBuffer(gl.ARRAY_BUFFER, m.batchGLBuffers.normals);
        gl.vertexAttribPointer(shader.inNormal, 3, gl.FLOAT, false, 0, 0); 
        // Get model mat & render
        var batchNodeList = batch.nodeList;
        var batchNodeNum = batchNodeList.length;
        var offset = 0;
        var max_obj = m.maxObjPerBatch;
        var method = m.renderType;
        for(var n=0;n<batchNodeNum;n++)
        {
          this.modeMatBuf.set( batchNodeList[n].modelMat.data, 16*offset);
          offset++;
          if(offset== max_obj || n==(batchNodeNum-1) )
          {
            // render
            gl.uniformMatrix4fv(shader.modelMat , false, this.modeMatBuf);
            if (method == GEW_TRIANGLES_NON_INDICES) 
            {
              var ver_num = (m.vertices.length / 3)*offset ;
              gl.drawArrays(gl.TRIANGLES, 0, ver_num);
            }
            else if(method== GEW_TRIANGLES_INDICES)
            {
              gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, m.batchGLBuffers.indices);
              var indicesNum = m.indices[0].length*offset;
              gl.drawElements(gl.TRIANGLES,indicesNum,gl.UNSIGNED_SHORT,0);
            }
            offset = 0;
          }
        }                
      }
    }    
    else if (this.batchType == GEW_STATIC_BATCH) 
    {
      var bList = this.batches;
      var bLen = bList.length;
      for (var i = 0; i < bLen; i++) 
      {
        var batch = bList[i];
        gl.uniformMatrix4fv(shader.modelViewProjectionMat, false, viewProjMat.getGLArray());
        var normalMat = new gewMat4();
        var modelMat = new gewMat4();
        gl.uniformMatrix4fv(shader.normalMat, false, normalMat.data);
        gl.uniformMatrix4fv(shader.modelMat, false, modelMat.data);
        batch.render(this);
      }
    }
  }
  if(!this.faceCulling)
    gl.enable(gl.CULL_FACE);
  this.isRendering = false;
}
